#include "Client.h"

#include <Game/GameManager.h>
#include <Account/AccountManager.h>
#include <Render/RenderManager.h>

using namespace Network;

Client::Client()
: port("2345"), ip_address("127.0.0.1"), quit(false), 
	logger (NULL), net_game(NULL), gameMgr(NULL), accountMgr(NULL), renderMgr(NULL)
{
}

Client::~Client()
{	
	if(net_game)
	{
		net_game->disconnect();
		delete net_game;
	}

	if(accountMgr)
		delete accountMgr;

	if(gameMgr)
		delete gameMgr;

	if(renderMgr)
		delete renderMgr;

	if(logger)
		delete logger;
}

void Client::exec()
{
	if(port == CL_String() || ip_address == CL_String())
		return;

	logger = new CL_ConsoleLogger();

	net_game = new CL_NetGameClient();
	slots.connect(net_game->sig_connected(), this, &Client::onConnected);
	slots.connect(net_game->sig_disconnected(), this, &Client::onDisconnected);
	slots.connect(net_game->sig_event_received(), this, &Client::onEventReceived);

	net_game->connect(ip_address, port);
	renderMgr = new Render::RenderManager();
	accountMgr = new Account::AccountManager(*this);
	gameMgr = new Game::GameManager(*this);

	const unsigned int pulse_ms = 10;		//This should probably be configurable from some config script/txt-file/xml
	while(!quit)
	{
		CL_KeepAlive::process(pulse_ms);	//timeout every 10ms
		if(accountMgr->isLoggedIn())
			gameMgr->update(pulse_ms);		//Do a game world update step here
		else
			accountMgr->update(pulse_ms);	//Do account update step here
		bool keep_running = renderMgr->update(pulse_ms);			//Do graphics update step here
		if(!keep_running)
			quit = true;
	}
	net_game->disconnect();
	cl_log_event("Network", "Client disconnected");

	delete net_game;
	net_game = NULL;

	delete accountMgr;
	accountMgr = NULL;

	delete gameMgr;
	gameMgr = NULL;

	delete renderMgr;
	renderMgr = NULL;

	delete logger;
	logger = NULL;
}

void Client::onConnected()
{
	bool handled_event = accountMgr->getLoginEvents().dispatch(CL_NetGameEvent("Connection-Accepted"));
	if(!handled_event)
		cl_log_event("events", "Unhandled event: %1", "Failed to handle connection accept event");
}

void Client::onDisconnected()
{
	bool handled_event = accountMgr->getLoginEvents().dispatch(CL_NetGameEvent("Connection-Disconnected"));
	if(!handled_event)
		cl_log_event("events", "Unhandled event: %1", "Failed to handle connection disconnected event");

	quit = true;
}

void Client::onEventReceived(const CL_NetGameEvent &e)
{
	cl_log_event("Network", cl_format("Event received %1", e.get_name()));

	bool handled_event = false;
	
	if(accountMgr->isLoggedIn())
		handled_event = gameMgr->getGameEvents().dispatch(e);
	else
		handled_event = accountMgr->getLoginEvents().dispatch(e);

	if(!handled_event)
		cl_log_event("events", "Unhandled event: %1", e.to_string());
}

void Client::sendEvent(const CL_NetGameEvent &gameEvent)
{
	if(net_game)
		net_game->send_event(gameEvent);
}
